import gosu.Font;
import gosu.Color;
import gosu.Image;

import org.jruby.*;
import org.jruby.runtime.*;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.javasupport.JavaUtil;
import org.jruby.anno.JRubyMethod;
import static org.jruby.RubyNumeric.*;


public class FontProxy extends RubyObject {
  private static ObjectAllocator ALLOCATOR = new ObjectAllocator() {
    public IRubyObject allocate(Ruby runtime, RubyClass klass) {
      return new FontProxy(runtime, klass);
    }
  };

  private Font _font;

  private Ruby _runtime;

  public static void createFontClass(Ruby runtime) {
    RubyModule mGosu = runtime.getModule("Gosu");
    RubyClass cFont = mGosu.defineClassUnder("Font", runtime.getObject(), ALLOCATOR);

    cFont.defineAnnotatedMethods(FontProxy.class);
  }


  public FontProxy(Ruby runtime, RubyClass type) {
    super(runtime, type);
    _runtime = runtime;
  }


  public Font getFont() { return _font; }


  @JRubyMethod(name = "initialize",
               required = 3,
               frame = true,
               visibility = Visibility.PRIVATE)
  public IRubyObject initialize(IRubyObject window, IRubyObject fontName, IRubyObject height) {
    try {
      _font = new Font(((WindowProxy) window).getWindow(), ((RubyString) fontName).toString(), fix2int(height));
    } catch (RuntimeException e) {
      throw _runtime.newRuntimeError(e.getMessage());
    }
    return this;
  }


  @JRubyMethod(name = "draw",
               required = 4,
               optional = 4)
  public IRubyObject draw(IRubyObject[] args) {
    String text = args[0].asString().getUnicodeValue();
    double x = num2dbl(args[1]);
    double y = num2dbl(args[2]);
    double z = num2dbl(args[3]);

    switch (args.length) {
      case 4:
        _font.draw(text, x, y, z);
        break;
      case 5:
        _font.draw(text, x, y, z, num2dbl(args[4]), 1.0);
        break;
      case 6:
        _font.draw(text, x, y, z, num2dbl(args[4]), num2dbl(args[5]));
        break;
      default: { // 7 or 8
        Color c = WindowProxy.getColorFrom(args[6]);

        int mode = Image.DEFAULT;
        if (args.length == 8) {
          mode = WindowProxy.getAlphaModeFrom(_runtime, args[7]);
        }

        _font.draw(text, x, y, z, num2dbl(args[4]), num2dbl(args[5]), c, mode);
      }
    }

    return _runtime.getNil();
  }


  @JRubyMethod(name = "draw_rot",
               required = 5,
               optional = 4)
  public IRubyObject drawRot(IRubyObject[] args) {
    String text = args[0].asString().getUnicodeValue();
    double x = num2dbl(args[1]);
    double y = num2dbl(args[2]);
    double z = num2dbl(args[3]);
    double angle = num2dbl(args[4]);

    switch (args.length) {
      case 5:
        _font.drawRot(text, x, y, z, angle);
        break;
      case 6:
        _font.drawRot(text, x, y, z, angle, num2dbl(args[5]), 1.0);
        break;
      case 7:
        _font.drawRot(text, x, y, z, angle, num2dbl(args[5]), num2dbl(args[6]));
        break;
      default: { // 8 or 9
        Color c = WindowProxy.getColorFrom(args[7]);

        int mode = Image.DEFAULT;
        if (args.length == 9) {
          mode = WindowProxy.getAlphaModeFrom(_runtime, args[8]);
        }

        _font.drawRot(text, x, y, z, angle, num2dbl(args[5]), num2dbl(args[6]), c, mode);
      }
    }

    return _runtime.getNil();
  }


  @JRubyMethod(name = "draw_rel",
               required = 6,
               optional = 4)
  public IRubyObject drawRel(IRubyObject[] args) {
    String text = args[0].asString().getUnicodeValue();
    double x = num2dbl(args[1]);
    double y = num2dbl(args[2]);
    double z = num2dbl(args[3]);
    double relX = num2dbl(args[4]);
    double relY = num2dbl(args[5]);

    switch (args.length) {
      case 6:
        _font.drawRel(text, x, y, z, relX, relY);
        break;
      case 7:
        _font.drawRel(text, x, y, z, relX, relY, num2dbl(args[6]), 1.0);
        break;
      case 8:
        _font.drawRel(text, x, y, z, relX, relY, num2dbl(args[6]), num2dbl(args[7]));
        break;
      default: { // 9 or 10
        Color c = WindowProxy.getColorFrom(args[8]);

        int mode = Image.DEFAULT;
        if (args.length == 10) {
          mode = WindowProxy.getAlphaModeFrom(_runtime, args[9]);
        }

        _font.drawRel(text, x, y, z, relX, relY, num2dbl(args[6]), num2dbl(args[7]), c, mode);
      }
    }

    return _runtime.getNil();
  }


  @JRubyMethod(name = "text_width",
               required = 1,
               optional = 1)
  public IRubyObject textWidth(IRubyObject[] args) {
    double width = _font.textWidth(args[0].toString());
    if (args.length > 1) {
      return _runtime.newFloat(width * num2dbl(args[1]));
    }
    return _runtime.newFloat(width);
  }


  @JRubyMethod(name = "height")
  public IRubyObject height() {
    return _runtime.newFixnum(_font.getHeight());
  }
}
